﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SlimDX.Direct3D9;

namespace Gype.UI.D3D9
{
    internal class Image9 : Image
    {
        internal Image9(Rendertarget9 target, System.Drawing.Bitmap image)
            : base(image)
        {
            mTarget = target;
            Width = image.Width;
            Height = image.Height;

            mVertexShader = new ShaderCompiler<VertexShader>(mTarget.GraphicsDevice, Shaders.Image, "VertexMain", "vs_3_0");
            mPixelShader = new ShaderCompiler<PixelShader>(mTarget.GraphicsDevice, Shaders.Image, "PixelMain", "ps_3_0");

            mViewportParam = mVertexShader.ConstantTable["viewportSize"];
            mTransformParam = mVertexShader.ConstantTable["transformMatrix"];

            initTextureFromImage(image);
        }

        protected override void initTextureFromImage(System.Drawing.Bitmap image)
        {
            base.initTextureFromImage(image);

            mTexture = new Texture(mTarget.GraphicsDevice, image.Width, image.Height, 1, Usage.AutoGenerateMipMap, Format.A8R8G8B8, Pool.Managed);
            var surface = mTexture.GetSurfaceLevel(0);

            var bmpBits = image.LockBits(new System.Drawing.Rectangle(0, 0, image.Width, image.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            SlimDX.DataStream strm = new SlimDX.DataStream(bmpBits.Scan0, image.Width * image.Height * 4, true, true);
            Surface.FromStream(surface, strm, Filter.Default, 0, Format.A8R8G8B8, 4 * image.Width, new System.Drawing.Rectangle(0, 0, image.Width, image.Height));
            image.UnlockBits(bmpBits);

            surface.Dispose();

            mTexture.GenerateMipSublevels();
        }

        public override void SaveAsPng(string filename)
        {
            Texture.ToFile(mTexture, filename, ImageFileFormat.Png);
        }

        public void DrawImage(System.Drawing.RectangleF srcRect, System.Drawing.RectangleF dstRect)
        {
            var vertices = mTarget.CreateTriangleList(new SlimDX.Vector2(dstRect.X, dstRect.Y), new SlimDX.Vector2(dstRect.Width, dstRect.Height), new SlimDX.Color4(1, 1, 1, 1));
            float minX = srcRect.X / Width;
            float maxX = (srcRect.X + srcRect.Width) / Width;
            float minY = srcRect.Y / Height;
            float maxY = (srcRect.Y + srcRect.Height) / Height;

            vertices[0].TexCoord = new SlimDX.Vector2(minX, minY);
            vertices[1].TexCoord = new SlimDX.Vector2(maxX, minY);
            vertices[2].TexCoord = new SlimDX.Vector2(minX, maxY);
            vertices[3].TexCoord = new SlimDX.Vector2(maxX, minY);
            vertices[4].TexCoord = new SlimDX.Vector2(maxX, maxY);
            vertices[5].TexCoord = new SlimDX.Vector2(minX, maxY);

            var dev = mTarget.GraphicsDevice;
            dev.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Linear);
            dev.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Linear);
            dev.SetSamplerState(0, SamplerState.MipFilter, TextureFilter.Linear);

            mTarget.GraphicsDevice.VertexShader = mVertexShader.Shader;
            mTarget.GraphicsDevice.PixelShader = mPixelShader.Shader;

            mPixelShader.SetValue(new ConstantDescription() { RegisterIndex = 0 }, mTexture);
            mVertexShader.SetValue(mTransformParam, mTarget.Transform);
            mVertexShader.SetValue(mViewportParam, mTarget.Viewport);

            mTarget.GraphicsDevice.VertexDeclaration = mTarget.UIVertexDeclaration;
            mTarget.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, 2, vertices);

            mTarget.GraphicsDevice.VertexShader = null;
            mTarget.GraphicsDevice.PixelShader = null;
        }

        private Rendertarget9 mTarget;
        private Texture mTexture;
        private ShaderCompiler<VertexShader> mVertexShader;
        private ShaderCompiler<PixelShader> mPixelShader;
        ConstantDescription mViewportParam;
        ConstantDescription mTransformParam;
    }
}
